# Copyright (c) 2018 Presto Labs Pte. Ltd.
# Author: inkyu

from collections import namedtuple

L2Amounts = namedtuple('L2Amounts', [
    'balance_amt',
    'position_amt',
    'reserve_amt',
])

L2Balance = namedtuple('L2Balance', ['base_balance', 'quote_balance'])


class L2Sizer(object):
  def __init__(self, l2_config):
    self._l2_config = l2_config
    self._l2_executor = None

  def set_l2_executor(self, l2_executor):
    self._l2_executor = l2_executor


class SpotL2Sizer(L2Sizer):
  def __init__(self, l2_config):
    assert not l2_config.parent.is_futures
    super().__init__(l2_config)

  def get_relpos(self):
    balance = self._l2_executor.mm_executor.og.get_balance(self._l2_config.key)
    corrected_balance = balance - self._l2_config.reserve_balance
    width = self._l2_config.max_pos - self._l2_config.reserve_balance
    if abs(width) < 1e-6:
      return 0
    else:
      return corrected_balance / width

  def get_balance(self):
    base_balance = self._l2_executor.mm_executor.og.get_balance(self._l2_config.key)
    quote_balance = self._l2_executor.mm_executor.og.get_balance(
        self._l2_config.parent.quote_currencies[0])
    if base_balance is None or quote_balance is None:
      return None
    return L2Balance(base_balance, quote_balance)

  def position_amts(self, prices, l2_balance):
    reserve = self._l2_config.reserve_balance
    return L2Amounts(
        balance_amt=prices.midp0 * l2_balance.base_balance,
        position_amt=prices.midp0 * (l2_balance.base_balance - reserve),
        reserve_amt=prices.midp0 * reserve,
    )


class FuturesL2Sizer(L2Sizer):
  def __init__(self, l2_config):
    assert l2_config.parent.is_futures
    super().__init__(l2_config)

  def get_relpos(self):
    position = self._l2_executor.mm_executor.query_unbiased_position()
    width = self._l2_config.max_pos
    if abs(width) < 1e-6:
      return 0
    else:
      return position / width

  def get_balance(self):
    if self._l2_executor.mm_executor:
      base_balance = self._l2_executor.mm_executor.og.get_balance(self._l2_config.key)
      return L2Balance(base_balance, None)
    else:
      return None

  def position_amts(self, prices, l2_balance):
    reserve = self._l2_config.reserve_balance
    return L2Amounts(
        balance_amt=prices.midp0 * l2_balance.base_balance,
        position_amt=prices.midp0 * (l2_balance.base_balance - reserve),
        reserve_amt=prices.midp0 * reserve,
    )
